home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / ANSI / c-client / smtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-18  |  8.3 KB  |  267 lines

  1. /*
  2.  * Program:    Simple Mail Transfer Protocol (SMTP) routines
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    27 July 1988
  13.  * Last Edited:    18 March 1993
  14.  *
  15.  * Sponsorship:    The original version of this work was developed in the
  16.  *        Symbolic Systems Resources Group of the Knowledge Systems
  17.  *        Laboratory at Stanford University in 1987-88, and was funded
  18.  *        by the Biomedical Research Technology Program of the National
  19.  *        Institutes of Health under grant number RR-00785.
  20.  *
  21.  * Original version Copyright 1988 by The Leland Stanford Junior University.
  22.  * Copyright 1993 by the University of Washington.
  23.  *
  24.  *  Permission to use, copy, modify, and distribute this software and its
  25.  * documentation for any purpose and without fee is hereby granted, provided
  26.  * that the above copyright notices appear in all copies and that both the
  27.  * above copyright notices and this permission notice appear in supporting
  28.  * documentation, and that the name of the University of Washington or The
  29.  * Leland Stanford Junior University not be used in advertising or publicity
  30.  * pertaining to distribution of the software without specific, written prior
  31.  * permission.  This software is made available "as is", and
  32.  * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
  33.  * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
  34.  * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  35.  * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
  36.  * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
  37.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  38.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  39.  * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
  40.  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  41.  *
  42.  */
  43.  
  44. #include <ctype.h>
  45. #include <stdio.h>
  46. #include "mail.h"
  47. #include "osdep.h"
  48. #include "smtp.h"
  49. #include "rfc822.h"
  50. #include "misc.h"
  51.  
  52. /* Mail Transfer Protocol open connection
  53.  * Accepts: service host list
  54.  *        initial debugging flag
  55.  * Returns: T on success, NIL on failure
  56.  */
  57.  
  58. SMTPSTREAM *smtp_open (char **hostlist,long debug)
  59. {
  60.   SMTPSTREAM *stream = NIL;
  61.   void *tcpstream;
  62.   char tmp[MAILTMPLEN];
  63.   if (!(hostlist && *hostlist)) mm_log ("Missing MTP service host",ERROR);
  64.   else do {            /* try to open connection */
  65.     if (tcpstream = tcp_open (*hostlist,SMTPTCPPORT)) {
  66.                 /* default local host */
  67.       if (!lhostn) lhostn = cpystr (tcp_localhost (tcpstream));
  68.       stream = (SMTPSTREAM *) fs_get (sizeof (SMTPSTREAM));
  69.       stream->tcpstream = tcpstream;
  70.       stream->debug = debug;
  71.       stream->reply = NIL;
  72.                 /* get SMTP greeting */
  73.       if (smtp_reply (stream) == SMTPGREET &&
  74.       ((smtp_send (stream,"HELO",tcp_localhost (tcpstream)) == SMTPOK) ||
  75.        ((!strcmp ("localhost",lcase (strcpy (tmp,*hostlist)))) &&
  76.         (smtp_send (stream,"HELO","localhost") == SMTPOK))))
  77.     return stream;        /* success return */
  78.       smtp_close (stream);    /* otherwise punt stream */
  79.     }
  80.   } while (*++hostlist);    /* try next server */
  81.   return NIL;
  82. }
  83.  
  84.  
  85. /* Mail Transfer Protocol close connection
  86.  * Accepts: stream
  87.  */
  88.  
  89. void smtp_close (SMTPSTREAM *stream)
  90. {
  91.   if (stream) {            /* send "QUIT" */
  92.     smtp_send (stream,"QUIT",NIL);
  93.                 /* close TCP connection */
  94.     tcp_close (stream->tcpstream);
  95.     if (stream->reply) fs_give ((void **) &stream->reply);
  96.     fs_give ((void **) &stream);/* flush the stream */
  97.   }
  98. }
  99.  
  100. /* Mail Transfer Protocol deliver mail
  101.  * Accepts: stream
  102.  *        delivery option (MAIL, SEND, SAML, SOML)
  103.  *        message envelope
  104.  *        message body
  105.  * Returns: T on success, NIL on failure
  106.  */
  107.  
  108. long smtp_mail (SMTPSTREAM *stream,char *type,ENVELOPE *env,BODY *body)
  109. {
  110.   char tmp[8*MAILTMPLEN];
  111.   long error = NIL;
  112.   if (!(env->to || env->cc || env->bcc)) {
  113.                   /* no recipients in request */
  114.     smtp_fake (stream,SMTPHARDERROR,"No recipients specified");
  115.     return NIL;
  116.   }
  117.                   /* make sure stream is in good shape */
  118.   smtp_send (stream,"RSET",NIL);
  119.   strcpy (tmp,"FROM:<");    /* compose "MAIL FROM:<return-path>" */
  120.   rfc822_address (tmp,env->return_path);
  121.   strcat (tmp,">");
  122.                 /* send "MAIL FROM" command */
  123.   if (!(smtp_send (stream,type,tmp) == SMTPOK)) return NIL;
  124.                 /* negotiate the recipients */
  125.   if (env->to) smtp_rcpt (stream,env->to,&error);
  126.   if (env->cc) smtp_rcpt (stream,env->cc,&error);
  127.   if (env->bcc) smtp_rcpt (stream,env->bcc,&error);
  128.   if (error) {            /* any recipients failed? */
  129.                       /* reset the stream */
  130.     smtp_send (stream,"RSET",NIL);
  131.     smtp_fake (stream,SMTPHARDERROR,"One or more recipients failed");
  132.     return NIL;
  133.   }
  134.                 /* negotiate data command */
  135.   if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL;
  136.                 /* set up error in case failure */
  137.   smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  138.                 /* output data, return success status */
  139.   return rfc822_output (tmp,env,body,smtp_soutr,stream->tcpstream) &&
  140.     (smtp_send (stream,".",NIL) == SMTPOK);
  141. }
  142.  
  143. /* Mail Transfer Protocol turn on debugging telemetry
  144.  * Accepts: stream
  145.  */
  146.  
  147. void smtp_debug (SMTPSTREAM *stream)
  148. {
  149.   stream->debug = T;        /* turn on protocol telemetry */
  150. }
  151.  
  152.  
  153. /* Mail Transfer Protocol turn off debugging telemetry
  154.  * Accepts: stream
  155.  */
  156.  
  157. void smtp_nodebug (SMTPSTREAM *stream)
  158. {
  159.   stream->debug = NIL;        /* turn off protocol telemetry */
  160. }
  161.  
  162. /* Internal routines */
  163.  
  164.  
  165. /* Simple Mail Transfer Protocol send recipient
  166.  * Accepts: SMTP stream
  167.  *        address list
  168.  *        pointer to error flag
  169.  */
  170.  
  171. void smtp_rcpt (SMTPSTREAM *stream,ADDRESS *adr,long *error)
  172. {
  173.   char tmp[MAILTMPLEN];
  174.   while (adr) {
  175.                 /* clear any former error */
  176.     if (adr->error) fs_give ((void **) &adr->error);
  177.     if (adr->host) {        /* ignore group syntax */
  178.       strcpy (tmp,"TO:<");    /* compose "RCPT TO:<return-path>" */
  179.       rfc822_address (tmp,adr);
  180.       strcat (tmp,">");
  181.                 /* send "RCPT TO" command */
  182.       if (!(smtp_send (stream,"RCPT",tmp) == SMTPOK)) {
  183.     *error = T;        /* note that an error occurred */
  184.     adr->error = cpystr (stream->reply);
  185.       }
  186.     }
  187.     adr = adr->next;        /* do any subsequent recipients */
  188.   }
  189. }
  190.  
  191.  
  192. /* Simple Mail Transfer Protocol send command
  193.  * Accepts: SMTP stream
  194.  *        text
  195.  * Returns: reply code
  196.  */
  197.  
  198. long smtp_send (SMTPSTREAM *stream,char *command,char *args)
  199. {
  200.   char tmp[MAILTMPLEN];
  201.                 /* build the complete command */
  202.   if (args) sprintf (tmp,"%s %s",command,args);
  203.   else strcpy (tmp,command);
  204.   if (stream->debug) mm_dlog (tmp);
  205.   strcat (tmp,"\015\012");
  206.                 /* send the command */
  207.   return tcp_soutr (stream->tcpstream,tmp) ? smtp_reply (stream) :
  208.     smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  209. }
  210.  
  211. /* Simple Mail Transfer Protocol get reply
  212.  * Accepts: SMTP stream
  213.  * Returns: reply code
  214.  */
  215.  
  216. long smtp_reply (SMTPSTREAM *stream)
  217. {
  218.                 /* flush old reply */
  219.   if (stream->reply) fs_give ((void **) &stream->reply);
  220.                   /* get reply */
  221.   if (!(stream->reply = tcp_getline (stream->tcpstream)))
  222.     return smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  223.   if (stream->debug) mm_dlog (stream->reply);
  224.                 /* handle continuation by recursion */
  225.   return (stream->reply[3]=='-') ? smtp_reply (stream) : atoi (stream->reply);
  226. }
  227.  
  228.  
  229. /* Simple Mail Transfer Protocol set fake error
  230.  * Accepts: SMTP stream
  231.  *        SMTP error code
  232.  *        error text
  233.  * Returns: error code
  234.  */
  235.  
  236. long smtp_fake (SMTPSTREAM *stream,long code,char *text)
  237. {
  238.                 /* flush any old reply */
  239.   if (stream->reply ) fs_give ((void **) &stream->reply);
  240.                   /* set up pseudo-reply string */
  241.   stream->reply = (char *) fs_get (20+strlen (text));
  242.   sprintf (stream->reply,"%ld %s",code,text);
  243.   return code;            /* return error code */
  244. }
  245.  
  246. /* Simple Mail Transfer Protocol filter mail
  247.  * Accepts: stream
  248.  *        string
  249.  * Returns: T on success, NIL on failure
  250.  */
  251.  
  252. long smtp_soutr (void *stream,char *s)
  253. {
  254.   char c,*t;
  255.                 /* find lines beginning with a "." */
  256.   while (t = strstr (s,"\015\012.")) {
  257.     c = *(t += 3);        /* remember next character after "." */
  258.     *t = '\0';            /* tie off string */
  259.                 /* output prefix */
  260.     if (!tcp_soutr (stream,s)) return NIL;
  261.     *t = c;            /* restore delimiter */
  262.     s = t - 1;            /* push pointer up to the "." */
  263.   }
  264.                 /* output remainder of text */
  265.   return *s ? tcp_soutr (stream,s) : T;
  266. }
  267.